﻿using Encloser.Packed;
using System;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace Encloser
{
    public class Logger
    {
        private const string LOG_SUFFIX = ".log";
        private static readonly bool debug = false;
        private static TextBox logBox;
        private static string logPath;

#if DEBUG
        static Logger() { debug = true; }
#endif
        public static Result Register(TextBox textBox, string path)
        {
            if (ValidUtils.IsEmpty(textBox, path)) return Result.INVALID_PARAMETERS;
            if (textBox.IsDisposed) return Result.Failed("日志输出框无效");
            lock (LOG_SUFFIX) logBox = textBox;
            if (!Directory.Exists(path)) try { Directory.CreateDirectory(path); } catch (Exception e) { return Result.Failed("创建日志目录失败", e); }
            lock (LOG_SUFFIX) logPath = path;
            return Result.OK;
        }

        public static string Trace(string content, int length = 32)
        {
            if (length < 8) length = 8;
            else if (length > 1024) length = 1024;
            var id = GenerateUUID(length);
            Log(LogLevel.Info, content + $" [{id}]");
            return id;
        }

        private static string GenerateUUID(int length)
        {
            var sb = new StringBuilder();
            var r = new Random();
            for (var i = 0; i < length; i++)
            {
                var k = r.Next(62);
                if (k < 10) sb.Append((char)('0' + k));
                else if (k < 36) sb.Append((char)('A' + k - 10));
                else sb.Append((char)('a' + k - 36));
            }
            return sb.ToString();
        }

        public static void Info(string content)
        {
            Log(LogLevel.Info, content);
        }

        public static void Debug(string content)
        {
            Log(LogLevel.Debug, content);
        }

        public static void Warn(Exception e)
        {
            if (e != null) Log(LogLevel.Warn, e.Message, e);
        }

        public static void Warn(string content, Exception e = null)
        {
            Log(LogLevel.Warn, content, e);
        }

        public static void Warn(Result result)
        {
            if (result != null) result.Catch((msg, ex) => Log(LogLevel.Warn, msg, ex));
        }

        public static void Warn<T>(string content, Result result)
        {
            if (result != null) result.Catch((msg, ex) => Log(LogLevel.Warn, content, ex));
        }

        public static void Error(Exception e)
        {
            if (e != null) Log(LogLevel.Error, e.Message, e);
        }

        public static void Error(string content, Exception e = null)
        {
            Log(LogLevel.Error, content, e);
        }

        public static void Error(Result result)
        {
            if (result != null) result.Catch((msg, ex) => Log(LogLevel.Error, msg, ex));
        }

        public static void Error(string errMsg, Result result)
        {
            if (result != null) result.Catch((msg, ex) => Log(LogLevel.Error, errMsg, ex));
        }

        public static void Log(LogLevel logLevel, string content, Exception e = null)
        {
            if (logLevel == LogLevel.Debug && !debug) return;
            content = content ?? string.Empty;
            var time = DateTime.Now;
            var text = $"{time.ToDateTimeString(true)} [{logLevel}]{content}\r\n";
            lock (LOG_SUFFIX)
            {
                Append(text);
                if (e == null || logPath == null) return;
                try
                {
                    File.AppendAllText(Path.Combine(logPath, time.ToDateString() + LOG_SUFFIX), $"{text}{e.GetType().Name}:{e.Message}\r\n{e.StackTrace}\r\n");
                }
                catch (Exception ex)
                {
                    Append($"{time.ToDateTimeString(true)} [{LogLevel.Warn}]保存日志数据失败\r\n{ex.StackTrace}\r\n");
                }
            }
        }

        private static void Append(string text)
        {
            if (logBox != null)
            {
                if (logBox.Text.Length + text.Length > logBox.MaxLength)
                {
                    var i = logBox.Text.IndexOf("\r\n", logBox.MaxLength / 2);
                    if (i == -1) logBox.Clear();
                    else logBox.Text = logBox.Text.Substring(i + 2);
                }
                logBox.AppendText(text);
            }
        }
    }
}
